// MongoDB connector
// Copyright (C) 2011-2012 Jani Kajala. Licensed under MIT-license.
// Dependencies: Node.js, mongodb (mongodb-native), async (caolan/async)

var mongo = require( 'mongodb' );
var async = require( 'async' );

/** 
 * Connects to MongoDB and optionally initializes specified Collections as member variables of MongoDBC. 
 * @param config Configuration options: mongoHost, mongoPort, verbose
 * @param db_name DB name to connect to
 * @param db_collection_names Array of collection names to initialize as member variables to MongoDBC 
 * @param next function(err,self) to call after init
 */
function MongoDBC( config, db_name, db_collection_names, next ) {
	var host = typeof config.mongoHost != 'undefined' ? config.mongoHost : 'localhost';
	var port = typeof config.mongoPort != 'undefined' ? config.mongoHost : mongo.Connection.DEFAULT_PORT;
	var verbose = typeof config.verbose != 'undefined' ? config.verbose : false;
	var self = this;
	
	var opt = {
		auto_reconnect: true
	};
	this.dbServer = new mongo.Server( host, port, opt );
	this.db = new mongo.Db( db_name, self.dbServer, {} );
	this.verbose = verbose;
	
	if (self.verbose)
		console.log( "MongoDBC: Connecting %s:%s", host, port );
	
	self.db.open( function(err,database) {
		if (err) {console.error( "MongoDBC: Connecting to DB failed: %s", err ); return next(err);}
		
		if (self.verbose)
			console.log( "MongoDBC: Connected ok" );

		self.db = database;
		if (db_collection_names)
			self.collections( db_collection_names, next );
		else
			next(null,self);
	} );
};

/**
 * Initializes specified Collections as member variables of MongoDBC, or lists available collections if called without initializer list.
 * If called without collection name array then the function lists all Collections by name and calls next(err,collections).
 * If called with collection name array then the function initializes listed Collections and calls user function next(err,self).
 * After initializations collections can be accessed by member variable name, e.g. 'users' collection is dbc.users.
 * @param db_collection_names Optional array of collection names to initialize as member variables to MongoDBC. 
 */
MongoDBC.prototype.collections = function( db_collection_names, next ) {
	var self = this;
	
	if ( typeof db_collection_names == 'function' )
		return self.db.collections( db_collection_names, next );

	async.forEach( db_collection_names, function(collection_name,next1) {
		self.db.collection( collection_name, function(err,collection) {
			if (err) {console.error( "MongoDBC: Collection %s initialization failed: %s", collection_name, err ); return next1(err);}
			
			self[collection_name] = collection;
			if (self.verbose) console.log( "MongoDBC: Collection %s initialized", collection_name );
			next1(err);
		} );
	}, function(err) {
		next(err,self);
	} ); 
};

/** Returns MongoDB ObjectID from string (or object as is if it's not string). */
MongoDBC.prototype.id = function(_id) {
	return typeof _id==='string' ? new db.ObjectID(_id) : _id;
};

/** MongoDB ObjectID type. */
MongoDBC.prototype.ObjectID = mongo.ObjectID;

/** MongoDB Binary type. */
MongoDBC.prototype.Binary = mongo.Binary;

module.exports = MongoDBC;
